﻿#region File and License Information
/*
<File>
	<License>
		Copyright © 2009 - 2017, Daniel Vaughan. All rights reserved.
		This file is part of Calcium (http://calciumsdk.net), 
		which is released under the MIT License.
		See file /Documentation/License.txt for details.
	</License>
	<CreationDate>2010-08-12 14:13:55Z</CreationDate>
</File>
*/
#endregion

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Outcoder.Concurrency
{
	public static class ReaderWriterLockSlimExtensions
	{
		public static void PerformUsingReadLock(
			this ReaderWriterLockSlim readerWriterLockSlim, Action action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				action();

				return;
			}

			try
			{
				readerWriterLockSlim.EnterReadLock();
				action();
			}
			finally
			{
				readerWriterLockSlim.ExitReadLock();
			}
		}

		public static async Task PerformUsingReadLockAsync(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				await action();

				return;
			}

			try
			{
				readerWriterLockSlim.EnterReadLock();

				await action();
			}
			finally
			{
				readerWriterLockSlim.ExitReadLock();
			}
		}

		public static T PerformUsingReadLock<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return action();
			}

			try
			{
				readerWriterLockSlim.EnterReadLock();

				return action();
			}
			finally
			{
				readerWriterLockSlim.ExitReadLock();
			}
		}

		public static async Task<T> PerformUsingReadLockAsync<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task<T>> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return await action();
			}

			try
			{
				readerWriterLockSlim.EnterReadLock();
				return await action();
			}
			finally
			{
				readerWriterLockSlim.ExitReadLock();
			}
		}

		public static void PerformUsingWriteLock(
			this ReaderWriterLockSlim readerWriterLockSlim, Action action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				action();
				return;
			}

			try
			{
				readerWriterLockSlim.EnterWriteLock();
				action();
			}
			finally
			{
				readerWriterLockSlim.ExitWriteLock();
			}
		}

		public static async Task PerformUsingWriteLockAsync(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				await action();

				return;
			}

			try
			{
				readerWriterLockSlim.EnterWriteLock();

				await action();
			}
			finally
			{
				readerWriterLockSlim.ExitWriteLock();
			}
		}

		public static T PerformUsingWriteLock<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return action();
			}

			try
			{
				readerWriterLockSlim.EnterWriteLock();
				return action();
			}
			finally
			{
				readerWriterLockSlim.ExitWriteLock();
			}
		}

		public static async Task<T> PerformUsingWriteLockAsync<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task<T>> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return await action();
			}

			try
			{
				readerWriterLockSlim.EnterWriteLock();
				return await action();
			}
			finally
			{
				readerWriterLockSlim.ExitWriteLock();
			}
		}

		public static void PerformUsingUpgradeableReadLock(
			this ReaderWriterLockSlim readerWriterLockSlim, Action action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				action();

				return;
			}

			try
			{
				readerWriterLockSlim.EnterUpgradeableReadLock();

				action();
			}
			finally
			{
				readerWriterLockSlim.ExitUpgradeableReadLock();
			}
		}

		public static async Task PerformUsingUpgradeableReadLockAsync(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				await action();

				return;
			}

			try
			{
				readerWriterLockSlim.EnterUpgradeableReadLock();

				await action();
			}
			finally
			{
				readerWriterLockSlim.ExitUpgradeableReadLock();
			}
		}

		public static T PerformUsingUpgradeableReadLock<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return action();
			}

			try
			{
				readerWriterLockSlim.EnterUpgradeableReadLock();
				return action();
			}
			finally
			{
				readerWriterLockSlim.ExitUpgradeableReadLock();
			}
		}

		public static async Task<T> PerformUsingUpgradeableReadLockAsync<T>(
			this ReaderWriterLockSlim readerWriterLockSlim, Func<Task<T>> action, bool performLock = true)
		{
			ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
			ArgumentValidator.AssertNotNull(action, "action");

			if (!performLock)
			{
				return await action();
			}

			try
			{
				readerWriterLockSlim.EnterUpgradeableReadLock();
				return await action();
			}
			finally
			{
				readerWriterLockSlim.ExitUpgradeableReadLock();
			}
		}
	}
}